package com.gitee.huxing.course.common.utils;

import com.gitee.huxing.course.domain.module.PlatFormOrderDO;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import java.util.stream.Collectors;

/**
 * @Description: 自定义一个id生成处理
 * 64位生成规则【首位是符号位，代表正副，所以实际有效是63位】：
 * 41位时间戳 |10位进程号 |12位计数器
 *
 * 41位时间戳：
 * 注意：这里没有直接使用时间戳，因为直接使用的话只能用到2039-09-07 23:47:35
 * 这里采用（当前时间戳-初始时间戳）。最多这样可以使用69年【(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69】
 * 10位机器：最多1023台机器
 * 12位计数器：每毫秒最多生成4095条记录
 * 这里可以根据项目中实际情况，调整每个位置的长度，比如分布式集群机器数量比较少，可以缩减机器的位数，增加计数器位数
 *
 * 使用注意事项：
 * 1、必须关闭时钟同步；
 * 2、currentTimeMillis一经定义，不可修改；
 * 3、并发量太高的时候，超过了4095，未做处理；
 * 4、最大不超过64位
 *
 * 自测性能：一秒能有三四十万的数据产生。
 * @ProjectName: JavaCourse
 * @Package: com.gitee.huxing.course.common.utils
 * @ClassName: IDGeneratorUtil
 * @Author: huxing
 * @DateTime: 2021-09-17 下午3:45
 */
public class IDGeneratorUtil {

    /**
     * 初始时间戳：2017-1-1 0:0:0
     * 一经定义，不可修改
     */
    private static final long initTimeMillis = 1483200000929L;

    /**
     * 进程。
     * 这里也可以手动指定每台实例的ID号；或者通过ZK的临时递增节点自动获取。
     * 固定值
     */
    private static final int pid = 3;

    /**
     * 原子 计数器
     * 需要保证线程安全
     */
    private static AtomicLong counter = new AtomicLong();

    private static volatile long currentTimeMillis = System.currentTimeMillis() - initTimeMillis;

    private static volatile long lastTimeMillis = currentTimeMillis;

    /** 默认首位为0 **/
    private static final long TYPE = 0;

    /**
     * @Description: 计算并生成时间戳
     * @Author: huxing
     * @return long
     * @Date: 2021/9/17 下午3:47
     **/
    public static synchronized long nextId() {
        long series = counter.getAndIncrement();
        //单位毫秒内计时器满了，需要重新计时
        if (series >= (1 << 12) - 1) {
            //等待到下一秒
            while (lastTimeMillis == currentTimeMillis) {
                currentTimeMillis = System.currentTimeMillis() - initTimeMillis;
            }
            lastTimeMillis = currentTimeMillis;
            counter.set(0);
            series = counter.getAndIncrement();
        }
        return TYPE + (currentTimeMillis << 22) | (pid << 12) | series;
    }


    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
//        List<Integer> counts = new ArrayList<>(1000000);
//        for (int i = 0; i< 1000000; i++){
//            counts.add(i);
//        }
        List<PlatFormOrderDO> list = new ArrayList<>(1000000);
        for (int i = 0; i< 1000000; i++){
            list.add(PlatFormOrderDO.createBuilderTest());
        }
        // 创建100w条数据
//        counts.stream().parallel().forEach(index -> {
//            list.set(index, PlatFormOrderDO.createBuilderTest());
//        });
        long endTime = System.currentTimeMillis();
        System.out.println("耗时: " + (endTime - startTime) + "ms");
    }
}
